/**
 * @file Bzip2Format.cpp
 * @brief BZIP2格式插件实现
 * @details 实现了BZIP2格式的压缩和解压缩功能
 */

#include "Bzip2Format.h"
#include <File.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
#include <String.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/**
 * @brief 构造函数
 */
Bzip2Format::Bzip2Format()
{
    // 构造函数不需要特殊初始化
}

/**
 * @brief 析构函数
 */
Bzip2Format::~Bzip2Format()
{
    // 析构函数不需要特殊清理
}

/**
 * @brief 获取插件支持的格式名称
 * @return 格式名称
 */
BString Bzip2Format::GetFormatName() const
{
    return BString("BZIP2");
}

/**
 * @brief 获取插件支持的文件扩展名列表
 * @return 扩展名列表，以分号分隔
 */
BString Bzip2Format::GetSupportedExtensions() const
{
    return BString(".bz2;.tar.bz2;.tbz2");
}

/**
 * @brief 检查插件是否支持指定的文件
 * @param filePath 文件路径
 * @return 是否支持
 */
bool Bzip2Format::CanHandle(const char *filePath) const
{
    if (filePath == NULL)
    {
        return false;
    }

    // 检查文件扩展名
    BString path(filePath);
    if (path.IFindLast(".bz2") >= 0 || path.IFindLast(".tbz2") >= 0)
    {
        return _IsBzip2File(filePath);
    }

    return false;
}

/**
 * @brief 压缩文件或目录
 * @param sourcePath 源文件或目录路径
 * @param targetPath 目标压缩文件路径
 * @return 操作是否成功
 */
bool Bzip2Format::Compress(const char *sourcePath, const char *targetPath)
{
#ifndef HAVE_BZIP2
    printf("错误：未安装bzip2库，无法执行BZIP2格式压缩\n");
    return false;
#else
    if (sourcePath == NULL || targetPath == NULL)
    {
        printf("错误：源路径或目标路径为空\n");
        return false;
    }

    // 检查源路径是否存在
    BEntry sourceEntry(sourcePath);
    if (!sourceEntry.Exists())
    {
        printf("错误：源文件或目录不存在：%s\n", sourcePath);
        return false;
    }

    // 构建压缩命令
    BString command;

    // 检查是否为tar.bz2格式
    BString targetStr(targetPath);
    bool isTarBz2 = targetStr.IFindLast(".tar.bz2") >= 0 || targetStr.IFindLast(".tbz2") >= 0;

    if (isTarBz2)
    {
        // 使用tar命令创建tar.bz2文件
        if (sourceEntry.IsDirectory())
        {
            // 压缩目录
            command.SetTo("tar -cjf \"");
            command.Append(targetPath);
            command.Append("\" -C \"");
            command.Append(sourcePath);
            command.Append("\" .");
        }
        else
        {
            // 压缩单个文件
            BPath path(sourcePath);
            command.SetTo("tar -cjf \"");
            command.Append(targetPath);
            command.Append("\" -C \"");
            command.Append(path.Path());
            command.Append("\" \"");
            command.Append(path.Leaf());
            command.Append("\"");
        }
    }
    else
    {
        // 使用bzip2命令压缩单个文件
        if (sourceEntry.IsDirectory())
        {
            printf("错误：BZIP2格式不支持直接压缩目录，请使用TAR.BZ2格式\n");
            return false;
        }

        // 复制文件到目标位置（不含.bz2扩展名）
        BString tempPath(targetPath);
        if (tempPath.IFindLast(".bz2") >= 0)
        {
            tempPath.Truncate(tempPath.Length() - 4);
        }

        command.SetTo("cp \"");
        command.Append(sourcePath);
        command.Append("\" \"");
        command.Append(tempPath);
        command.Append("\" && bzip2 -f \"");
        command.Append(tempPath);
        command.Append("\"");
    }

    // 执行压缩命令
    return _ExecuteBzip2Command(command.String());
#endif
}

/**
 * @brief 解压缩文件
 * @param sourcePath 源压缩文件路径
 * @param targetPath 目标解压目录
 * @return 操作是否成功
 */
bool Bzip2Format::Extract(const char *sourcePath, const char *targetPath)
{
#ifndef HAVE_BZIP2
    printf("错误：未安装bzip2库，无法执行BZIP2格式解压缩\n");
    return false;
#else
    if (sourcePath == NULL || targetPath == NULL)
    {
        printf("错误：源路径或目标路径为空\n");
        return false;
    }

    // 检查源文件是否存在
    BEntry sourceEntry(sourcePath);
    if (!sourceEntry.Exists() || sourceEntry.IsDirectory())
    {
        printf("错误：源压缩文件不存在或不是文件：%s\n", sourcePath);
        return false;
    }

    // 检查是否为BZIP2文件
    if (!_IsBzip2File(sourcePath))
    {
        printf("错误：文件不是有效的BZIP2格式：%s\n", sourcePath);
        return false;
    }

    // 检查目标目录是否存在，如果不存在则创建
    BEntry targetEntry(targetPath);
    if (!targetEntry.Exists())
    {
        status_t result = create_directory(targetPath, 0755);
        if (result != B_OK)
        {
            printf("错误：无法创建目标目录：%s\n", targetPath);
            return false;
        }
    }
    else if (!targetEntry.IsDirectory())
    {
        printf("错误：目标路径不是目录：%s\n", targetPath);
        return false;
    }
#endif

    // 构建解压命令
    BString command;

    // 检查是否为tar.bz2格式
    bool isTarBz2 = _IsTarBz2File(sourcePath);

    if (isTarBz2)
    {
        // 使用tar命令解压tar.bz2文件
        command.SetTo("tar -xjf \"");
        command.Append(sourcePath);
        command.Append("\" -C \"");
        command.Append(targetPath);
        command.Append("\"");
    }
    else
    {
        // 使用bzip2命令解压单个文件
        BPath path(sourcePath);
        BString fileName(path.Leaf());

        // 移除.bz2扩展名
        if (fileName.IFindLast(".bz2") >= 0)
        {
            fileName.Truncate(fileName.Length() - 4);
        }

        command.SetTo("bzip2 -dc \"");
        command.Append(sourcePath);
        command.Append("\" > \"");
        command.Append(targetPath);
        command.Append("/");
        command.Append(fileName);
        command.Append("\"");
    }

    // 执行解压命令
    return _ExecuteBzip2Command(command.String());
}

/**
 * @brief 列出压缩文件中的内容
 * @param archivePath 压缩文件路径
 * @return 内容列表字符串
 */
BString Bzip2Format::ListContents(const char *archivePath)
{
#ifndef HAVE_BZIP2
    return BString("错误：未安装bzip2库，无法列出BZIP2格式内容");
#else
    if (archivePath == NULL)
    {
        return BString("错误：压缩文件路径为空");
    }

    // 检查文件是否存在
    BEntry entry(archivePath);
    if (!entry.Exists() || entry.IsDirectory())
    {
        return BString("错误：压缩文件不存在或不是文件");
    }

    // 检查是否为BZIP2文件
    if (!_IsBzip2File(archivePath))
    {
        return BString("错误：文件不是有效的BZIP2格式");
    }
#endif

    // 构建命令
    BString command;

    // 检查是否为tar.bz2格式
    bool isTarBz2 = _IsTarBz2File(archivePath);

    if (isTarBz2)
    {
        // 使用tar命令列出tar.bz2文件内容
        command.SetTo("tar -tjf \"");
        command.Append(archivePath);
        command.Append("\"");
    }
    else
    {
        // 对于单个bzip2文件，只显示文件名（去掉.bz2扩展名）
        BPath path(archivePath);
        BString fileName(path.Leaf());

        // 移除.bz2扩展名
        if (fileName.IFindLast(".bz2") >= 0)
        {
            fileName.Truncate(fileName.Length() - 4);
        }

        return fileName;
    }

    // 执行命令并获取输出
    FILE *pipe = popen(command.String(), "r");
    if (pipe == NULL)
    {
        return BString("错误：无法执行命令");
    }

    // 读取命令输出
    char buffer[1024];
    BString result;

    while (fgets(buffer, sizeof(buffer), pipe) != NULL)
    {
        result.Append(buffer);
    }

    pclose(pipe);

    return result;
}

/**
 * @brief 检查文件是否为BZIP2格式
 * @param filePath 文件路径
 * @return 是否为BZIP2格式
 */
bool Bzip2Format::_IsBzip2File(const char *filePath) const
{
    if (filePath == NULL)
    {
        return false;
    }

    // 打开文件
    BFile file(filePath, B_READ_ONLY);
    if (file.InitCheck() != B_OK)
    {
        return false;
    }

    // 读取文件头部
    uint8 header[3];
    ssize_t bytesRead = file.Read(header, sizeof(header));

    // 检查是否成功读取足够的字节
    if (bytesRead != sizeof(header))
    {
        return false;
    }

    // 检查BZIP2文件头部标识（'B' 'Z' 'h'）
    if (header[0] == 'B' && header[1] == 'Z' && header[2] == 'h')
    {
        return true;
    }

    return false;
}

#ifndef HAVE_BZIP2
// 当没有bzip2库时，提供一个警告信息
void _ShowBzip2MissingWarning()
{
    static bool warningShown = false;
    if (!warningShown)
    {
        printf("警告：未安装bzip2库，BZ2格式支持受限\n");
        warningShown = true;
    }
}
#endif

/**
 * @brief 执行BZIP2命令行工具
 * @param command 命令行字符串
 * @return 执行是否成功
 */
bool Bzip2Format::_ExecuteBzip2Command(const char *command) const
{
#ifndef HAVE_BZIP2
    printf("错误：未安装bzip2库，无法执行bzip2命令\n");
    return false;
#else
    if (command == NULL)
    {
        return false;
    }

    // 执行命令
    int result = system(command);

    // 检查命令执行结果
    if (result != 0)
    {
        printf("命令执行失败：%s\n", command);
        return false;
    }

    return true;
#endif
}

/**
 * @brief 检查是否为TAR.BZ2格式
 * @param filePath 文件路径
 * @return 是否为TAR.BZ2格式
 */
bool Bzip2Format::_IsTarBz2File(const char *filePath) const
{
    if (filePath == NULL)
    {
        return false;
    }

    // 检查文件扩展名
    BString path(filePath);
    return (path.IFindLast(".tar.bz2") >= 0 || path.IFindLast(".tbz2") >= 0);
}